git flow migration step 2 recommendation
written by Chat GPT 5
[스텝 2] 자동화 고도화(라벨 감지 → 승급 PR 자동 생성, 스테이징 배포)
1) dev 기능 분류 자동화(라벨 기반)
-
정책: feature → dev PR에
ready-for-stage
라벨이 붙은 상태로 dev에 머지되면, 봇이 자동으로 stage 승급 PR 생성 -
준비:
-
라벨:
ready-for-stage
-
권한: GitHub Actions에
contents: write
,pull-requests: write
-
머지 전략: feature PR은 squash merge 유지(승급 단위가 명확)
-
2) 승급 PR 자동 생성 워크플로
-
이벤트:
pull_request
closed ondev
+ 라벨 확인 -
구현 예:
.github/workflows/promotion.yml
name: Promote to Stage on Label on: pull_request: types: [closed] branches: [ "dev" ] permissions: contents: write pull-requests: write jobs: promote: if: > github.event.pull_request.merged == true && contains(join(fromJson(toJson(github.event.pull_request.labels)).*.name), 'ready-for-stage') runs-on: ubuntu-latest steps: - name: Extract source branch id: src run: echo "branch=${{ github.event.pull_request.head.ref }}" >> $GITHUB_OUTPUT - uses: actions/checkout@v4 with: ref: ${{ steps.src.outputs.branch }} fetch-depth: 0 - name: Push promotion branch (optional) run: | git fetch origin stage git checkout -b promote/${{ steps.src.outputs.branch }} origin/stage git merge --no-ff --no-edit origin/${{ steps.src.outputs.branch }} || exit 10 git push -u origin promote/${{ steps.src.outputs.branch }} - name: Open PR to stage uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.GITHUB_TOKEN }} branch: promote/${{ steps.src.outputs.branch }} base: stage title: "promote: ${{ steps.src.outputs.branch }} → stage" body: | Auto-promotion PR from feature `${{ steps.src.outputs.branch }}`. Source PR: #${{ github.event.pull_request.number }} Label: ready-for-stage
충돌 시
exit 10
로 실패 → 수동 승급(아래 2-2로 전환)
2-2) 라벨 미부착·자동 실패 시 수동 승급
-
수동: feature → stage PR(스텝1의 4번과 동일)
-
메시지 컨벤션:
-
Title:
promote: feature/foo → stage
-
Body: 원 PR 링크, 테스트/QA 항목
-
3) 스테이징 환경 배포 자동화
-
인프라: Elastic Beanstalk 등 스테이징 환경 생성(예:
app-staging
) -
Secrets:
STAGE_*
시크릿 등록 -
워크플로:
.github/workflows/deploy-stage.yml
name: Deploy Stage on: push: branches: [ "stage" ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: pnpm i --frozen-lockfile - run: pnpm build - run: ./scripts/deploy.sh stage env: STAGE_API_KEY: ${{ secrets.STAGE_API_KEY }}
-
QA 체크리스트(자동+수동):
-
헬스체크 200/OK
-
주요 API e2e 스펙(로그인/결제/정산/알림) 스모크 패스
-
플래그 기본값/환경 변수 확인
-
4) stage → main 머지, 태그, 배포(동일)
-
stage → main PR 템플릿 강화:
-
포함 PR 리스트 자동 삽입(액션으로 생성 가능)
-
릴리스노트 초안 자동 생성(커밋 메시지/PR body 집계)
-
-
배포는 스텝1의 prod 워크플로 재사용
-
태그 정책:
-
patch: 버그 수정/미세 변경
-
minor: 기능 추가(하위 호환)
-
major: 파괴적 변경 + 마이그레이션
-
5) main → dev 백머지(이번 스텝2는 수동 PR)
-
이유: 자동화 이전 대비, 이번 스텝2에선 릴리즈 경계 명확화/감사성 목적
-
PR 템플릿(요지):
-
제목:
chore(backmerge): main → dev @ vX.Y.Z
-
본문 체크:
-
충돌 해결 내역 요약
-
스키마/플래그 변화 없음(or 절차)
-
릴노 링크
-
-
-
충돌 없으면 fast-forward 머지 권장
부가: 운영 규칙 요약(변경·추가)
-
라벨 부착 시점: feature → dev PR 생성 시
ready-for-stage
(기본), QA 미완이면 미부착 -
승급 단위: 최대한 “작은 PR” 유지
-
핫픽스: main에서 hotfix/*** 분기 → main 머지/태그/배포 → 항상 stage/dev로 백포트(스텝1=자동, 스텝2=수동PR)
-
릴리즈 노트: stage→main PR에서 집중 작성, 백머지 커밋/PR에는 릴노 링크만 남김
-
모니터링: 배포 후 30~60분 집중관찰(에러레이트/결제성공률/핵심 KPI)
2025-09-25 Backmerge-on-tag
name: Back-merge to stage & dev on release tag
on:
push:
tags:
- "v*.*.*" # 세머버 태그만 트리거
permissions:
contents: write
pull-requests: write
jobs:
backmerge:
runs-on: ubuntu-latest
strategy:
matrix:
target: ["stage", "dev"]
steps:
- name: Extract tag & basic info
id: meta
run: |
TAG="${GITHUB_REF#refs/tags/}"
echo "tag=${TAG}" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Fetch all branches & tags
run: |
git fetch --all --tags
- name: Verify tag commit belongs to main
id: verify
run: |
TAG_SHA="$(git rev-list -n 1 "${{ steps.meta.outputs.tag }}")"
if git merge-base --is-ancestor "$TAG_SHA" origin/main; then
echo "sha=${TAG_SHA}" >> $GITHUB_OUTPUT
else
echo "::error::Tag commit is not on origin/main. Aborting."
exit 1
fi
- name: Prepare backmerge branch
id: prep
run: |
TARGET="${{ matrix.target }}"
TAG="${{ steps.meta.outputs.tag }}"
BR="chore/backmerge-${TARGET}-${TAG}"
# idempotency
git push origin --delete "$BR" 2>/dev/null || true
git branch -D "$BR" 2>/dev/null || true
git fetch origin "$TARGET"
git switch -c "$BR" "origin/${TARGET}"
# merge tag into target tip
set -e
git merge --no-ff --no-edit "${TAG}" || {
echo "::error::Merge conflict when merging ${TAG} into ${TARGET}. Resolve manually."
exit 1
}
# skip if no changes
if git diff --quiet "origin/${TARGET}...HEAD"; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
git push -u origin "$BR"
fi
- name: Open PR to target branch
if: steps.prep.outputs.skip == 'false'
id: cpr
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
base: ${{ matrix.target }}
branch: chore/backmerge-${{ matrix.target }}-${{ steps.meta.outputs.tag }}
title: "chore(backmerge): main → ${{ matrix.target }} @ ${{ steps.meta.outputs.tag }}"
body: |
Automated back-merge of release **${{ steps.meta.outputs.tag }}** into **${{ matrix.target }}**.
- Source: main @ tag `${{ steps.meta.outputs.tag }}`
- Target: `${{ matrix.target }}`
- Strategy: `git merge --no-ff ${{ steps.meta.outputs.tag }}`
- Auto-merge: enabled (squash) once required checks pass.
labels: |
backmerge
automerge
draft: false
# ✅ Auto-merge 활성화 (CI green 시 자동으로 머지됨)
- name: Enable auto-merge (squash)
if: steps.prep.outputs.skip == 'false'
uses: peter-evans/enable-pull-request-automerge@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
merge-method: squash
- name: No-op note
if: steps.prep.outputs.skip == 'true'
run: echo "No diff for ${{ matrix.target }}; PR skipped."
목적: 프로덕션 릴리즈(main)를 하위 환경에 동기화
동작 조건:
- Semantic versioning 태그 푸시 (
v*.*.*
) - 태그가 main 브랜치의 커밋을 가리켜야 함
동작 방식:
- 태그 커밋이 main 브랜치에 속하는지 검증
- Stage와 Dev 각각에 대해 병렬로:
- 백머지 브랜치 생성 (
chore/backmerge-{target}-{tag}
) - 태그를 타겟 브랜치로 merge (--no-ff)
- 변경사항이 있으면 PR 생성
- 자동 머지 활성화 (squash merge)
- 백머지 브랜치 생성 (
특징:
- Matrix strategy로 stage/dev 동시 처리
- 충돌 발생 시 수동 해결 필요
- CI 통과 시 자동으로 머지되어 수동 승인 불필요